Skip to content

fix(server): add backpressure to SSE event queues#19423

Open
BYK wants to merge 1 commit intoanomalyco:devfrom
BYK:fix/sse-backpressure
Open

fix(server): add backpressure to SSE event queues#19423
BYK wants to merge 1 commit intoanomalyco:devfrom
BYK:fix/sse-backpressure

Conversation

@BYK
Copy link
Copy Markdown
Contributor

@BYK BYK commented Mar 27, 2026

Issue for this PR

Closes #16697

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Adds backpressure to the AsyncQueue used by SSE endpoints to prevent unbounded memory growth when clients fall behind.

Root cause: AsyncQueue has no size limit. When an SSE client stalls (slow network, backgrounded tab, stalled proxy), Bus.subscribeAll keeps pushing JSON.stringify'd events into the queue without bound. In production this caused 187GB RSS (forensic report).

Fix: Add optional capacity parameter to AsyncQueue with drop-oldest behavior. When the queue exceeds capacity, oldest items are discarded. Set to 1024 items (~2MB at ~2KB avg event size) for both SSE endpoints (event.ts and global.ts). TUI queues remain unbounded since they are 1:1 request/response pairs that never accumulate.

The web UI already handles reconnection gracefully (full state reload on server.connected), so dropped events during a stall are recovered naturally.

3 files changed, ~7 lines.

How did you verify your code works?

  • Bus and snapshot tests pass
  • Verified queue drops oldest items when capacity exceeded
  • Existing SSE consumers (TUI) unaffected — no capacity parameter means unbounded

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

AsyncQueue is unbounded — when SSE clients fall behind (slow network,
stalled browser tab), JSON-serialized bus events accumulate without limit.
This caused 187GB RSS in production (anomalyco#16697).

Add optional capacity parameter to AsyncQueue with drop-oldest behavior.
Set to 1024 items (~2MB) for both SSE endpoints. TUI queues remain
unbounded (1:1 request/response, never accumulate).
@BYK BYK force-pushed the fix/sse-backpressure branch from 655f1a9 to 2631130 Compare April 1, 2026 18:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Multiple memory leaks cause unbounded RAM growth during extended TUI usage

1 participant